/**********************************************************************
// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.
//
// @@@ END COPYRIGHT @@@
**********************************************************************/
#ifndef RELENFORCER_H
#define RELENFORCER_H
/* -*-C++-*-
 *****************************************************************************
 *
 * File:         RelEnforcer.h
 * Description:  Enforcers for physical properties
 * Created:      3/6/95
 * Language:     C++
 *
 *
 *
 *
 *****************************************************************************
 */

// -----------------------------------------------------------------------

#include "RelExpr.h"
#include "PartFunc.h"

// -----------------------------------------------------------------------
// contents of this file
// -----------------------------------------------------------------------
class Sort;
class Exchange;

// -----------------------------------------------------------------------
// forward references
// -----------------------------------------------------------------------
class CostScalar;
class SimpleCostVector;
class CorrName;
class SearchKey;

///////////////////////////////////////////////////////////////////////////
// SortLogical node is a shortlived node to keep track of an 'order by'
// clause at the top level of a view.
// It is created during bind phase view expansion and is eliminated during
// the normalization phase.
// See method BindWA::bindView, RelRoot::transformNode 
// and SortLogical::normalizeNode for details.
///////////////////////////////////////////////////////////////////////////
class SortLogical : public RelExpr
{
public:
  SortLogical(RelExpr *child,
	      const ValueIdList &sortKey,
	      CollHeap *oHeap = CmpCommon::statementHeap()) :
       RelExpr(REL_SORT_LOGICAL,child, NULL, oHeap),
       sortKey_(sortKey)
  {}

  // Each operator supports a (virtual) method for performing
  // predicate pushdown and computing a "minimal" set of
  // characteristic input and characteristic output values.
  virtual RelExpr * normalizeNode(NormWA & normWARef);

  // accessor functions
  inline ValueIdList &getSortKey() { return sortKey_; }

  // get the degree of this node (it is a unary op).
  virtual Int32 getArity() const { return 1; };

private:

  // the sort key list
  ValueIdList sortKey_;       // the order of sort keys is relevant
};

// -----------------------------------------------------------------------
// The Sort operator returns the same rows as its child, but in a given
// sort order. It is generated by the sort enforcer rule in case where
// its parent node requires a specific sort order or an arrangement of
// columns. It can also take an ordered stream of rows from the child
// and extend an existing ordering key of the child
// (alreadySortedColumns_) by additional expressions.
// -----------------------------------------------------------------------
class Sort : public RelExpr
{
public:

  // constructors
  Sort(RelExpr *child,
	      CollHeap *oHeap = CmpCommon::statementHeap()) :
       RelExpr(REL_SORT,child,NULL,oHeap),
       sortNRows_(FALSE), 
       topNRows_(0),
       collectNFErrors_(FALSE),
       forcedHalloweenProtection_(FALSE),
       checkAccessToSelfRefTable_(FALSE)
	 {}
  Sort(RelExpr *child,
	      const ValueIdList &sortKey,
	      CollHeap *oHeap = CmpCommon::statementHeap()) :
       RelExpr(REL_SORT,child, NULL, oHeap),
       sortKey_(sortKey),
       sortNRows_(FALSE), 
       topNRows_(0),
       collectNFErrors_(FALSE),
       forcedHalloweenProtection_(FALSE),
       checkAccessToSelfRefTable_(FALSE)
	 {}
  inline Sort(RelExpr *child,
	      const ValueIdSet &arrangedCols) :
       RelExpr(REL_SORT,child),
       arrangedCols_(arrangedCols),
       sortNRows_(FALSE), 
       topNRows_(0),
    forcedHalloweenProtection_(FALSE),
    checkAccessToSelfRefTable_(FALSE),
    collectNFErrors_(FALSE)
	 {}

  virtual ~Sort();

  // get the degree of this node (it is a unary op).
  virtual Int32 getArity() const;

  virtual RelExpr * preCodeGen(Generator * generator,
			       const ValueIdSet & externalInputs,
			       ValueIdSet &pulledNewInputs);
  virtual short codeGen(Generator*);
  virtual void needSortedNRows(NABoolean val);
  NABoolean &sortNRows() {return sortNRows_;}

  virtual HashValue topHash();
  virtual NABoolean duplicateMatch(const RelExpr & other) const;
  virtual RelExpr * copyTopNode(RelExpr *derivedNode = NULL,
				CollHeap* outHeap = NULL);

  virtual NABoolean isLogical() const;
  virtual NABoolean isPhysical() const;

  // Cascades-related functions
  virtual CostMethod* costMethod() const;
  virtual Context* createContextForAChild(Context* myContext,
                     PlanWorkSpace* pws,
                     Lng32& childindex);

  virtual PhysicalProperty* synthPhysicalProperty(const Context* myContext,
                                                  const Lng32    planNumber,
                                                  PlanWorkSpace  *pws);

  void synthPartialSortKeyFromChild(const Context*);
  virtual void produceFinalSortKey();

  // get a printable string that identifies the operator
  virtual const NAString getText() const;

  // add all the expressions that are local to this
  // node to an existing list of expressions (used by GUI tool)
  virtual void addLocalExpr(LIST(ExprNode *) &xlist,
			    LIST(NAString) &llist) const;

  // accessor functions
  inline ValueIdList &getSortKey()                    { return sortKey_; }
  inline ValueIdList &getPartialSortKeyFromChild() 
                   { return PartialSortKeyFromChild_;} 
  inline ValueIdList &getPrefixSortKey()
                   { return PartialSortKeyFromChild_;}

  inline ValueIdSet &getArrangedCols()           { return arrangedCols_; }

  // The method gets refined since Sort may be a BMO depending on its inputs.
  virtual NABoolean isBigMemoryOperator(const PlanWorkSpace* pws,
                                        const Lng32 planNumber);

  virtual CostScalar getEstimatedRunTimeMemoryUsage(Generator *generator, NABoolean perNode, Lng32 *numStreams = NULL);

  virtual PlanPriority computeOperatorPriority
    (const Context* context,
     PlanWorkSpace *pws=NULL,
     Lng32 planNumber=0);

  inline void markAsHalloweenProtection() { forcedHalloweenProtection_= TRUE; }
  inline void setCollectNFErrors(NABoolean cf = TRUE) {collectNFErrors_ = cf;}
  inline NABoolean collectNFErrors() {return collectNFErrors_;}

  inline void doCheckAccessToSelfRefTable() { checkAccessToSelfRefTable_ = TRUE; }

  ExplainTuple *addSpecificExplainInfo(ExplainTupleMaster *explainTuple,
					      ComTdb * tdb,
					      Generator *generator);

  virtual NABoolean sortFromTop() { return FALSE; }
protected:

  // the sort key list
  ValueIdList sortKey_;       // the order of sort keys is relevant
  ValueIdSet  arrangedCols_;  // a "fuzzy" sort key, actual order can
                              // be determined later

  // set to TRUE, if top N sorted rows are needed.
  // See method needSortedNRows().
  NABoolean sortNRows_;

  // Introduced specifically to protect against halloween problem.
  // If a sort was chosen by the optimizer for any other reason,
  // this flag will be false.  It is set to true by NestJoin::preCodeGen.
  NABoolean forcedHalloweenProtection_;

  // A "halloween sort" needs to ensure that if it is parallel, but executes
  // in the same ESP as the generic update's TSJ flow node, then the Sort
  // will block until all scans are finished.  This logic is enforced in the 
  // PreCodeGen phase.  This next flag helps.
  NABoolean checkAccessToSelfRefTable_;

  // we keep track of order of input stream to see if it could be used
  // by order and/or arrangement requirements
  ValueIdList PartialSortKeyFromChild_;

  NABoolean collectNFErrors_;

  ULng32 topNRows_;

  short generateTdb(Generator * generator,
                    ComTdb * child_tdb,
                    ex_expr * sortKeyExpr,
                    ex_expr * sortRecExpr,
                    ULng32 sortKeyLen,
                    ULng32 sortRecLen,
                    ULng32 sortPrefixKeyLen,
                    ex_cri_desc * given_desc,
                    ex_cri_desc * returned_desc,
                    ex_cri_desc * work_cri_desc,
                    Lng32 saveNumEsps,
                    ExplainTuple *childExplainTuple,
                    NABoolean resizeCifRecord,
                    NABoolean considerBufferDefrag,
                    NABoolean operatorCIF = FALSE);

  //determine internal format
  /*
  virtual ExpTupleDesc::TupleDataFormat determineInternalFormat( const ValueIdList & valIdList,
                                                                    RelExpr * relExpr,
                                                                    NABoolean & resizeCifRecord,
                                                                    Generator * generator);*/

  ExpTupleDesc::TupleDataFormat determineInternalFormat( const ValueIdList & valIdList,
                                                         RelExpr * relExpr,
                                                         NABoolean & resizeCifRecord,
                                                         Generator * generator,
                                                         NABoolean bmo_affinity ,
                                                         NABoolean & considerBufferDefrag);

};

class SortFromTop : public Sort
{
public:

  // constructors
  SortFromTop(RelExpr *child,
	      CollHeap *oHeap = CmpCommon::statementHeap()) :
       Sort(child, oHeap)
  {}

  virtual RelExpr * preCodeGen(Generator * generator,
			       const ValueIdSet & externalInputs,
			       ValueIdSet &pulledNewInputs);
  virtual short codeGen(Generator*);

  virtual RelExpr * copyTopNode(RelExpr *derivedNode = NULL,
				CollHeap* outHeap = NULL);

  // get a printable string that identifies the operator
  virtual const NAString getText() const;

  virtual NABoolean sortFromTop() { return TRUE; }

  ValueIdList &getSortRecExpr() { return sortRecExpr_; }

private:
  // list of values to be used to create the input row to sort
  ValueIdList sortRecExpr_;       
};

// 
// preCodeGen (pcg) phase esp fragment. This class is used by over
// parallelization correction logic and is not related to FragmentDir.
//
class pcgEspFragment {

public:

  pcgEspFragment(CollHeap* heap) :
     childEsps_(heap), valid_(FALSE),totalRows_(csZero), newDoP_(0), 
     commonDoP_(0) {};

  ~pcgEspFragment() {};

  void addChild(Exchange* esp);

  void accumulateRows(CostScalar x) { totalRows_ += x; } ;

  CostScalar getTotaleRows() { return totalRows_; } ;

  NABoolean isValid() const { return valid_; };

  // reduce the dop at this fragment. 
  NABoolean tryToReduceDoP(); 

  // invalidate DoP for my fragment and my child fragments
  void invalidate();     

  // adjust the dop 
  void adjustDoP(Lng32 newDop);

  Lng32 getNewDop() { return newDoP_;}

protected:
  void setValid(NABoolean x) { valid_ = x; };

protected:
  NAArray<Exchange*> childEsps_;

  CostScalar totalRows_;  // total rows to be rocessed;

  Lng32 newDoP_;         // new proposed dop for the fragment 

  Lng32 commonDoP_;      // a common dop fro the 1st child esp with
                         // non-broadcast parf func, for other 
                         // non-broadcast child esps to match

  NABoolean valid_;      // whether this fragment is a candidate for
                         // over parallelization correction.
};


// -----------------------------------------------------------------------
// class Exchange
//
// An Exchange is used for realizing the parallel execution of query
// plan fragments (ESP parallelism) as well as for asynchronous
// communication between an ESP and the disk server process (DP2).
//
// The optimizer introduces an Exchange operator in the dataflow tree
// in order to send data from one process to another, either to change
// the plan execution location (DP2, ESP, Master), or to redistribute
// the workload to multiple processes.
//
// A process boundary to DP2 (DP2 exchange) is introduced when data or
// control needs to be returned from DP2. There are two flavors of
// DP2 exchanges, as described below.
//
// An ESP exchange introduces an Executor Server Process, or ESP when
// an operator in the query execution plan is expected to consume
// memory very heavily, or when a tree of operators implements a
// cpu-intensive operation that is likely to saturate the cpu, or
// asynchronous access to partitioned data can improve the throughput
// of an operator, or operator trees. It encapsulates parallelism as
// described by Goetz Graefe for the Volcano prototype.  Jim Gray
// calls the communication pattern created by the Exchange operator a
// "river".
//
// The Exchange that is implemented for the SQL/ARK optimizer is just
// another dataflow operator. It is represented using the notation
// Exchange(n:m), where m is the number of data streams it receives as
// its internal dataflow inputs and n is the number of data streams it
// produces as its output. In Cascades jargon, it is purely a physical
// operator and is a partition and location enforcer. We consistently
// use the term "stream" in preference over the term "partition",
// while referring to the input values received by an Exchange as well
// as the output values produced by it, because we view them to be
// orthognal to each other. For historical reasons, the PartitioningFunction
// classes use the term "partition" which is equivalent to the term
// "stream" in this context.
//
// In an attempt to disambiguate the terms input and output, we
// introduce two new terms "top" and "bottom" to classify the
// dataflow. We call the root of the query tree its "top" and
// the leaves of the query tree its "bottom":
//
//                   |   n "top" data stream(s) for the Exchange
//                   |
//                   X   an Exchange operator n:m
//                   |
//                   |   m "bottom" data stream(s) for the Exchange
//
//         Fig 1. A sample of dataflow through the Exchange
//
// After optimization, an Exchange node contains a descriptor that
// describes the partitioning characteristics of its top data streams,
// which include the number of data streams, the partitioning key
// columns as well as the partitioning function that will be used for
// creating them. The descriptor is implemented by the class
// PartitioningFunction.  The Exchange also contains another
// PartitioningFunction for describing its bottom data streams.
//
// -----------------------------------------------------------------------

class Exchange : public RelExpr
{
public:

  // constructor
  Exchange(RelExpr *childSubtree,
	   CollHeap *oHeap = CmpCommon::statementHeap())
    : RelExpr(REL_EXCHANGE,childSubtree, NULL, oHeap),
      topPartFunc_(NULL),
      bottomPartFunc_(NULL),
      bottomLocIsSet_(FALSE),
      isRedundant_(FALSE),
      skipRedundancyCheck_(FALSE),
      indexDesc_(NULL),
      partSearchKey_(NULL),
      DP2TransactionIndicator_(FALSE),
      numBMOs_(0),
      BMOsMemoryUsage_(0),
      isOverReverseScan_(FALSE),
      extractSelectList_(NULL),
      isExtractProducer_(FALSE),
      isExtractConsumer_(FALSE),
      upMessageBufferLength_(0),
      downMessageBufferLength_(0),
      forcedHalloweenProtection_(FALSE),
      halloweenSortIsMyChild_(FALSE),
      hash2RepartitioningWithSameKey_(FALSE),
      isAnESPAccess_(FALSE),
      pcgEspFragment_(oHeap)
   {}

  virtual ~Exchange();

  // get the degree of this node (it is a unary op).
  virtual Int32 getArity() const;

  // ---------------------------------------------------------------------
  // The Exchange operator that is seen by the optimizer denotes a
  // group of one or more operators, which are distinct from it, that
  // realize interprocess communication and parallel execution at run
  // time. There are three different groups of operators that can
  // replace the Exchange during code generation, namely,
  //
  // 1) a PartitionAccess, called a PA
  // 2) a SplitTop together with a PartitionAccess, called a PAPA
  // 3) a SplitTop, SendTop, SendBottom, SplitBottom group, which
  //    is only used when the Exchange executes within an ESP.
  //
  // The Exchange node is an enforcer for both plan execution location
  // (master, ESP, DP2) and partitioning.
  // ---------------------------------------------------------------------

  // ---------------------------------------------------------------------
  // Get the partitioning function for the top and bottom. The methods are
  // used by the (preCode) generator to avoid accessing physical props
  // directly.
  // ---------------------------------------------------------------------
  inline const PartitioningFunction * getTopPartitioningFunction() const
                                                  { return topPartFunc_; }
  inline const PartitioningFunction * getBottomPartitioningFunction() const
                                               { return bottomPartFunc_; }

  inline const IndexDesc * getIndexDesc() const     { return indexDesc_; }

  // ---------------------------------------------------------------------
  // Location for the plan rooted in this Exchange operator.
  // NOTE: both methods return FALSE if the location is undetermined.
  // ---------------------------------------------------------------------
  inline NABoolean isDP2Exchange() const
       { return (bottomLocIsSet_ AND bottomLocation_ == EXECUTE_IN_DP2); }
  inline NABoolean isEspExchange() const
       { return (bottomLocIsSet_ AND bottomLocation_ != EXECUTE_IN_DP2); }

  // ---------------------------------------------------------------------
  // Misc. methods required by the optimizer
  // ---------------------------------------------------------------------
  virtual RelExpr * copyTopNode(RelExpr *derivedNode = NULL,
				CollHeap* outHeap = NULL);

  virtual NABoolean isLogical() const;
  virtual NABoolean isPhysical() const;

  // Cascades-related functions
  virtual CostMethod* costMethod() const;
  virtual Context* createContextForAChild(Context* myContext,
                     PlanWorkSpace* pws,
                     Lng32& childIndex);

  virtual PhysicalProperty* synthPhysicalProperty(const Context *context,
                                                  const Lng32    planNumber,
                                                  PlanWorkSpace  *pws);

  // ---------------------------------------------------------------------
  // Methods used by the generator.
  // ---------------------------------------------------------------------
  virtual RelExpr * preCodeGen(Generator * generator,
			       const ValueIdSet & externalInputs,
			       ValueIdSet &pulledNewInputs);

  virtual short codeGen(Generator * generator);

  // -----------------------------------------------------
  // generate CONTROL QUERY SHAPE fragment for this node.
  // -----------------------------------------------------
  virtual short generateShape(CollHeap * space, char * buf, NAString * shapeStr = NULL);

  // ---------------------------------------------------------------------
  // The term partition input values is used for the values that
  // define the partitioning boundaries for each data stream that
  // flow into the bottom of the Exchange. The Exchange has to
  // propagate the values down to the source of the data streams,
  // which is either another Exchange or a DP2Scan.
  // ---------------------------------------------------------------------
  inline const ValueIdList &getBottomPartitionInputValues() const
                                        { return bottomPartInputValues_; }
  inline void setBottomPartitionInputValues(const ValueIdList &v)
                                           { bottomPartInputValues_ = v; }

  // ---------------------------------------------------------------------
  // get a printable string that identifies the operator
  // ---------------------------------------------------------------------
  virtual const NAString getText() const;

  // ---------------------------------------------------------------------
  // add all the expressions that are local to this
  // node to an existing list of expressions (used by GUI tool)
  // ---------------------------------------------------------------------
  virtual void addLocalExpr(LIST(ExprNode *) &xlist,
			    LIST(NAString) &llist) const;

  ExplainTuple *addSpecificExplainInfo(ExplainTupleMaster *explainTuple,
					      ComTdb * tdb,
					      Generator *generator);


  void  computeBufferLength(const Context*,
                            const CostScalar&,
                            const CostScalar&,
                            CostScalar&,
                            CostScalar&);

  inline void setDP2TransactionIndicator( NABoolean b )
                               { DP2TransactionIndicator_ = b; }
  inline NABoolean getDP2TransactionIndicator()
                               { return DP2TransactionIndicator_; }

  inline NABoolean isOverReverseScan() { return isOverReverseScan_ == TRUE;}
  void setOverReverseScan() { isOverReverseScan_=TRUE;}

  virtual PlanPriority computeOperatorPriority
   (const Context* context,
   PlanWorkSpace *pws=NULL,
   Lng32 planNumber=0);

  // for Hash2 or Hash1 pf functions, used in costing of probes
  NABoolean areProbesHashed(const ValueIdSet);

  // Does this exchange node only change # of partitions
  // the top and bottom partitioing key is still the same
  inline NABoolean hash2RepartitioningWithSameKey()
  { return hash2RepartitioningWithSameKey_;}

  inline void setNumBMOs(unsigned short num) { numBMOs_ = num; }
  inline unsigned short getNumBMOs() { return numBMOs_; }

  // set and get the total BMO memory usage of the fragment rooted
  // at this Exchange node
  inline void setBMOsMemoryUsage(CostScalar x) { BMOsMemoryUsage_ = x; }
  inline CostScalar getBMOsMemoryUsage() { return BMOsMemoryUsage_ ; }

  virtual CostScalar getEstimatedRunTimeMemoryUsage(Generator *generator, NABoolean perNode, Lng32 *numStreams = NULL);
  virtual double getEstimatedRunTimeMemoryUsage(Generator *generator, ComTdb * tdb);

  void setExtractProducerFlag() { isExtractProducer_ = TRUE; }
  NABoolean getExtractProducerFlag() { return isExtractProducer_; }

  void setExtractConsumerFlag() { isExtractConsumer_ = TRUE; }
  NABoolean getExtractConsumerFlag() { return isExtractConsumer_; }

  // Only valid after preCodeGen.  Halloween-related.
  NABoolean doesMerge() {return (sortKeyForMyOutput_.entries() != 0); }

  // Halloween-related.
  inline void markAsHalloweenProtection() 
                                  { forcedHalloweenProtection_ = TRUE; }

  inline void markHalloweenSortIsMyChild() { halloweenSortIsMyChild_ = TRUE; }

  // Three mutators for ESP Exchanges inserted during preCodeGen.   
  // Halloween-related.
  void doSkipRedundancyCheck() { skipRedundancyCheck_ = TRUE; }
  void setUpMessageBufferLength(CostScalar len) 
    { upMessageBufferLength_ = len; }
  void setDownMessageBufferLength( CostScalar len)
    { downMessageBufferLength_ = len; }

  inline NABoolean isAnESPAccess() const
  { return isAnESPAccess_;}

  inline void makeAnESPAccess()
  { isAnESPAccess_ = TRUE;}

  ExpTupleDesc::TupleDataFormat determineInternalFormat( const ValueIdList & valIdList,
                                                         RelExpr * relExpr,
                                                         NABoolean & resizeCifRecord,
                                                         Generator * generator,
                                                         NABoolean bmo_affinity,
                                                         NABoolean & considerBufferDefrag);

;


  // dop reduction
  void prepareDopReduction(Generator*);
  void doDopReduction();

  pcgEspFragment* getEspFragPCG() { return &pcgEspFragment_; };

  // Rules for enabling SeaMonster are encapsulated in this
  // method. Rules include: CQD SEAMONSTER ON or the env var
  // SQ_SEAMONSTER=1 is set, the exchange cannot be an extract
  // producer or consumer, and others.
  bool thisExchangeCanUseSM(BindWA *) const;

private:

  // ---------------------------------------------------------------------
  // PRIVATE METHODS
  // ---------------------------------------------------------------------

  // ---------------------------------------------------------------------
  // generate code (two different cases, for an ESP or for reading
  // a partitioned table in parallel)
  // ---------------------------------------------------------------------
  short codeGenForSplitTop(Generator * generator);
  short codeGenForESP(Generator * generator);
  void storePhysPropertiesInNode(const ValueIdList & );
  short generateMergeExpr(Generator * generator);


  // ---------------------------------------------------------------------
  // A method that interprets the CONTROL QUERY SHAPE ... to decide
  // what is desired by the user. The method modifies the required
  // properties for the child or sometimes even indicates that the
  // given plan should not be considered by returning NULL.
  // ---------------------------------------------------------------------
  ReqdPhysicalProperty * processCQS(const ReqdPhysicalProperty *rppForMe,
				    ReqdPhysicalProperty *rppForChild);

  // what kind of exchange is this
  // (both may return FALSE if this has not been determined yet)
  NABoolean isAPA() const;
  NABoolean isAPAPA() const;

  // Synthesize physical properties for exchange operator's current plan
  // extracted from a spcified context when child executes in DP2.
  //
  // Helper method for Exchange::synthPhysicalProperty()
  //
  PhysicalProperty*
  synthPhysicalPropertyDP2(const Context *myContext);

  // Synthesize physical properties for exchange operator's current plan
  // extracted from a spcified context when child executes in ESP.
  //
  // Helper method for Exchange::synthPhysicalProperty()
  //
  PhysicalProperty*
  synthPhysicalPropertyESP(const Context *myContext);

  // Helper method for Exchange::synthPhysicalProperty()
  // Synthesize those physical properties for exchange operator's that are common
  // to both case (child executes in DP2 and child executes in DP2)
  //
  PhysicalProperty*
  synthPhysicalPropertyFinalize(const Context *myContext,
                                PartitioningFunction *myPartFunc,
                                SortOrderTypeEnum sortOrderType,
                                PartitioningFunction *childPartFunc,
                                const PhysicalProperty *sppOfChild,
                                const ReqdPhysicalProperty *rppForMe,
                                PartitioningFunction* dp2SortOrderPartFunc);



private:

  // ---------------------------------------------------------------------
  // PRIVATE DATA: this data is stored in the Exchange node only AFTER
  // optimization. Before that time this data should be obtained from
  // the physical properties of the Exchange and/or its child.
  //
  // We have the policy that the code generator should not access
  // physical properties and therefore we store all the necessary data
  // for the code generator in private data members (see method
  // storePhysPropertiesInNode()).
  // ---------------------------------------------------------------------

  // ---------------------------------------------------------------------
  // Top and Bottom partitioning functions and bottom location
  // (set after physical properties are synthesized)
  // ---------------------------------------------------------------------
  const PartitioningFunction *topPartFunc_;
  const PartitioningFunction *bottomPartFunc_;
  NABoolean bottomLocIsSet_;
  PlanExecutionEnum bottomLocation_;
  NABoolean isRedundant_;
  NABoolean skipRedundancyCheck_;
  NABoolean isOverReverseScan_;

  const IndexDesc* indexDesc_;
  const SearchKey* partSearchKey_;

  // ---------------------------------------------------------------------
  // The bottomPartInputValues_ describes the layout of the partition
  // input values as they are sent to the child operators.
  //
  // For example, if a range partitioning function is used, then the
  // values are the begin key and the end key values for a given range.
  // For a range partitioning function, partition input values also
  // contain a boolean indicator
  // whether the end key is included (for the last key interval) or
  // excluded (all other intervals). Note that the begin key is always
  // included in the range. For example, if a partitioning key
  // contains four columns, the layout of the begin and end key values
  // in bottomPartInputValues_ is as shown below:
  //
  //   ----------------------------------------------------------------
  //   | bkv1 | bkv2 | bkv3 | bkv4 | ekv1 | ekv2 | ekv3 | ekv4 | excl |
  //   ----------------------------------------------------------------
  //   |<--- begin key values ---->|<----- end key values ---->|
  //
  // For a hash partitioning function, the part. input values contain
  // two integer values, indicating a range of hash classes.
  // ---------------------------------------------------------------------
  ValueIdList bottomPartInputValues_;   // values identifying the partition

  // ---------------------------------------------------------------------
  // If the required physical properties for this Exchange specify a
  // sort key or an arragement and the plan for the child that executes
  // in DP2 satisfies this requirement, then the Exchange cannot use
  // a non-blocking access on the child. The Exchange performs a logical
  // merge of the sorted data streams and produces an ordered stream of
  // rows as its own output. The sort key is provided by the child.
  // ---------------------------------------------------------------------
  ValueIdList sortKeyForMyOutput_;        // sort order produced by executor

  NABoolean DP2TransactionIndicator_; // set for compound statements

  unsigned short numBMOs_; // number of BMOs in this fragment

  CostScalar BMOsMemoryUsage_; // total amount of BMO memory usage in this fragment

  // Flag that indicates this exchange node only change # of partitions
  // the top and bottom partitioing key is still the same
  NABoolean hash2RepartitioningWithSameKey_;

  // For parallel extract. These fields are set during preCodeGen for
  // use by codeGen methods. Prior to preCodeGen these fields should
  // not be used.
  ValueIdList *extractSelectList_;
  NABoolean isExtractProducer_;
  NABoolean isExtractConsumer_;

  // calculated for Esp exchanges only in the optimizer
  CostScalar upMessageBufferLength_;
  CostScalar downMessageBufferLength_;

  // This flag tells if this (ESP) exchange was introduced specifically 
  // to protect against  halloween problem.  Part of solution 10-071204-9253.
  // See comments on generator/Generator.cpp.
  NABoolean forcedHalloweenProtection_;

  // This flag used in preCodeGen, in case Exchange is eliminated b/c is 
  // is redundant.
  NABoolean halloweenSortIsMyChild_;

   NABoolean isAnESPAccess_;

  // a pre-code-gen phase fragment rooted at this exchange
  pcgEspFragment pcgEspFragment_;

}; // class Exchange

#endif /* RELENFORCER_H */

